package com.google.zxing.client.android;

import java.io.IOException;
import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
import java.util.Set;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.Result;
import com.google.zxing.client.android.camera.CameraManager;

import android.app.AlertDialog;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;

public class CaptureFragment extends Fragment implements
	SurfaceHolder.Callback {

	private static final String TAG = CaptureFragment.class.getSimpleName();

	private CameraManager cameraManager;
	private CaptureActivityHandler handler;
	private Result savedResultToShow;
	private boolean hasSurface;
	private SurfaceView surfaceView ;
	private ViewfinderView viewfinderView;
	private Collection<BarcodeFormat> decodeFormats;
	private Map<DecodeHintType, Object> decodeHints;
	private String characterSet = Setting.CHRACTER_SET;
	private InactivityTimer inactivityTimer;
	private BeepManager beepManager;
	private AmbientLightManager ambientLightManager;
	
	private int width = Setting.SCAN_WIDTH ;
	private int height = Setting.SCAN_HEIGHT ;

	private int maskColor = 0;
	private int resultColor = 0;
	private int laserColor = 0;
	private int frameCornerColor = 0;
	private int resultPointColor = 0;
	
	private OnScanResultListener lResult = null ;

	ViewfinderView getViewfinderView() {
		return viewfinderView;
	}

	public Handler getHandler() {
		return handler;
	}

	CameraManager getCameraManager() {
		return cameraManager;
	}

	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		Window window = getActivity().getWindow();
		window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
		
	    Resources resources = getResources();
	    if (0 == maskColor) {
	    	maskColor = resources.getColor(R.color.viewfinder_mask);
	    }
	    if (0 == resultColor) {
	    	resultColor = resources.getColor(R.color.result_view);
	    }
	    if (0 == laserColor) {
	    	laserColor = resources.getColor(R.color.viewfinder_laser);
	    }
	    if (0 == frameCornerColor) {
	    	frameCornerColor = laserColor ;
	    }
	    if (0 == resultPointColor) {
	    	resultPointColor = resources.getColor(R.color.possible_result_points);
	    }
	}
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View contentView = View.inflate(getActivity(), R.layout.capture, null) ;
		viewfinderView = (ViewfinderView) contentView.findViewById(R.id.viewfinder_view);
		surfaceView = (SurfaceView) contentView.findViewById(R.id.preview_view);

		initViewFinderView() ;
		hasSurface = false;
		inactivityTimer = new InactivityTimer(getActivity());
		beepManager = new BeepManager(getActivity());
		ambientLightManager = new AmbientLightManager(getActivity());
		return contentView;
	}
	
	public void setOnScanResultListener(OnScanResultListener l) {
		this.lResult = l ;
	}
	
	public void setOrientation(boolean portrait) {
		Setting.PORTRAIT_MODE = portrait ;
	}
	
	public void setScanSize(int width, int height) {
		this.width = width ;
		this.height = height ;
	}
	
	public void setMaskColor(int color) {
		this.maskColor = color ;
	}
	
	public void setResultColor(int color) {
		this.resultColor = color ;
	}
	
	public void setLaserColor(int color) {
		this.laserColor = color ;
	}
	
	public void setFrameCornerColor(int color) {
		this.frameCornerColor = color ;
	}
	
	public void setResultPointColor(int color) {
		this.resultPointColor = color ;
	}
	
	public void setDecodeFormat(Set<BarcodeFormat> formats) {
		if (null == decodeFormats) {
			decodeFormats = EnumSet.noneOf(BarcodeFormat.class) ;
		} else {
			decodeFormats.clear();
		}
		decodeFormats.addAll(formats) ;
	}
	
	public void addDecodeHint(DecodeHintType hintType, Object hintData) {
		if (null == decodeHints) {
			decodeHints = new EnumMap<>(DecodeHintType.class) ;
		}
		decodeHints.put(hintType, hintData) ;
	}
	
	public void clearDecodeHints() {
		if (null != decodeHints) {
			decodeHints.clear();
		}
	}
	
	private void initViewFinderView() {
		viewfinderView.setMaskColor(maskColor);
		viewfinderView.setResultColor(resultColor);
		viewfinderView.setLaserColor(laserColor);
		viewfinderView.setFrameCornerColor(frameCornerColor);
		viewfinderView.setResultPointColor(resultPointColor);
	}

	@Override
	public void onResume() {
		super.onResume();

		// CameraManager must be initialized here, not in onCreate(). This is
		// necessary because we don't
		// want to open the camera driver and measure the screen size if we're
		// going to show the help on
		// first launch. That led to bugs where the scanning rectangle was the
		// wrong size and partially
		// off screen.
		cameraManager = new CameraManager(getActivity().getApplication());

		viewfinderView.setCameraManager(cameraManager);

		handler = null;

		resetStatusView();

		beepManager.updatePrefs();
		ambientLightManager.start(cameraManager);

		inactivityTimer.onResume();
		
		if (width > 0 && height > 0) {
			cameraManager.setManualFramingRect(width, height);
		}

		SurfaceHolder surfaceHolder = surfaceView.getHolder();
		if (hasSurface) {
			// The activity was paused but not stopped, so the surface still
			// exists. Therefore
			// surfaceCreated() won't be called, so init the camera here.
			initCamera(surfaceHolder);
		} else {
			// Install the callback and wait for surfaceCreated() to init the
			// camera.
			surfaceHolder.addCallback(this);
		}
	}

	@Override
	public void onPause() {
		if (handler != null) {
			handler.quitSynchronously();
			handler = null;
		}
		inactivityTimer.onPause();
		ambientLightManager.stop();
		beepManager.close();
		cameraManager.closeDriver();
		// historyManager = null; // Keep for onActivityResult
		if (!hasSurface && null != surfaceView) {
			SurfaceHolder surfaceHolder = surfaceView.getHolder();
			surfaceHolder.removeCallback(this);
		}
		super.onPause();
	}

	@Override
	public void onDestroyView() {
		inactivityTimer.shutdown();
		super.onDestroyView();
	}

	public boolean onKeyDown(int keyCode, KeyEvent event) {
		switch (keyCode) {
		case KeyEvent.KEYCODE_FOCUS:
		case KeyEvent.KEYCODE_CAMERA:
			// Handle these events so they don't launch the Camera app
			return true;
			// Use volume up/down to turn on light
		case KeyEvent.KEYCODE_VOLUME_DOWN:
			cameraManager.setTorch(false);
			return true;
		case KeyEvent.KEYCODE_VOLUME_UP:
			cameraManager.setTorch(true);
			return true;
		default : break ;
		}
		return false ;
	}

	private void decodeOrStoreSavedBitmap(Bitmap bitmap, Result result) {
		// Bitmap isn't used yet -- will be used soon
		if (handler == null) {
			savedResultToShow = result;
		} else {
			if (result != null) {
				savedResultToShow = result;
			}
			if (savedResultToShow != null) {
				Message message = Message.obtain(handler,
						MessageId.ID_DECODE_SUCCEEDED, savedResultToShow);
				handler.sendMessage(message);
			}
			savedResultToShow = null;
		}
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		if (holder == null) {
			Log.e(TAG,
					"*** WARNING *** surfaceCreated() gave us a null surface!");
		}
		if (!hasSurface) {
			hasSurface = true;
			initCamera(holder);
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		hasSurface = false;
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		
	}

	/**
	 * A valid barcode has been found, so give an indication of success and show
	 * the results.
	 * 
	 * @param rawResult
	 *            The contents of the barcode.
	 * @param scaleFactor
	 *            amount by which thumbnail was scaled
	 * @param barcode
	 *            A greyscale bitmap of the camera data which was decoded.
	 */
	public void handleDecode(Result rawResult, Bitmap barcode, float scaleFactor) {
		inactivityTimer.onActivity();

		// handle the result
		if (null != lResult) {
			lResult.onScanResult(rawResult, barcode);
		}
	}

	private void initCamera(SurfaceHolder surfaceHolder) {
		if (surfaceHolder == null) {
			throw new IllegalStateException("No SurfaceHolder provided");
		}
		if (cameraManager.isOpen()) {
			Log.w(TAG,
					"initCamera() while already open -- late SurfaceView callback?");
			return;
		}
		try {
			cameraManager.openDriver(surfaceHolder);
			// Creating the handler starts the preview, which can also throw a
			// RuntimeException.
			if (handler == null) {
				handler = new CaptureActivityHandler(this, decodeFormats,
						decodeHints, characterSet, cameraManager);
			}
			decodeOrStoreSavedBitmap(null, null);
		} catch (IOException ioe) {
			Log.w(TAG, ioe);
			displayFrameworkBugMessageAndExit();
		} catch (RuntimeException e) {
			// Barcode Scanner has seen crashes in the wild of this variety:
			// java.?lang.?RuntimeException: Fail to connect to camera service
			Log.w(TAG, "Unexpected error initializing camera", e);
			displayFrameworkBugMessageAndExit();
		}
	}

	private void displayFrameworkBugMessageAndExit() {
		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
		builder.setTitle(getString(R.string.app_name));
		builder.setMessage(getString(R.string.msg_camera_framework_bug));
		builder.setPositiveButton(R.string.button_ok, new FinishListener(getActivity()));
		builder.setOnCancelListener(new FinishListener(getActivity()));
		builder.show();
	}

	public void restartPreviewAfterDelay(long delayMS) {
		if (handler != null) {
			handler.sendEmptyMessageDelayed(MessageId.ID_RESTART_PREVIEW, delayMS);
		}
		resetStatusView();
	}

	private void resetStatusView() {
		viewfinderView.setVisibility(View.VISIBLE);
	}

	public void drawViewfinder() {
		viewfinderView.drawViewfinder();
	}
	
	/**
	 * 扫描结果监听
	 * @author turnleft
	 * @create 2015年8月21日
	 *
	 */
	public static interface OnScanResultListener {
		
		/**
		 * 监听扫描结果。
		 * @param rawResult
		 * @param barcode
		 */
		public void onScanResult(Result rawResult, Bitmap barcode) ;
		
	}
	
}
